use std::{
    fs::File,
    io::{BufWriter, Read, Write},
    path::PathBuf,
};

use clap::Args;
use zip::{write::FileOptions, ZipWriter};

#[derive(Debug, Args)]
pub struct PowerEqualResultOption {
    #[arg(help = "Certificate file")]
    key_file: PathBuf,
    #[arg(short, long, default_value = "false", help = "Export to power.conf")]
    export: bool,
    #[arg(
        short,
        long,
        default_value = "false",
        help = "Replace power.conf in given zip file, will override export option"
    )]
    zip_file: Option<PathBuf>,
}

pub fn calculate_equal_result(options: PowerEqualResultOption) {
    let cert = cert_lib::load_certificate(options.key_file).expect("load certificate failed");
    let result =
        cert_lib::calculate_power_euqal_result(cert).expect("calculate equal result failed");
    if let Some(zip_file) = options.zip_file {
        let mut buffer: Vec<u8> = Vec::new();
        {
            let mut buf_writer = BufWriter::new(&mut buffer);
            buf_writer
                .write("[Args]\n\n[Result]\n".as_bytes())
                .expect("write power.conf failed");
            buf_writer
                .write(result.as_bytes())
                .expect("write power.conf failed");
            buf_writer.flush().expect("write power.conf failed");
        }
        // 将zip_file的文件名增加一个`_replaced`后缀并形成一个新的位于相同目录的PathBuf实例。
        let mut zip_file_path = zip_file.clone();
        let file_name = zip_file_path.file_stem().unwrap().to_str().unwrap();
        let mut zip_file_name = file_name.to_string();
        zip_file_name.push_str("_replaced.");
        zip_file_name.push_str(&zip_file_path.extension().unwrap().to_string_lossy());
        zip_file_path.set_file_name(zip_file_name);
        // 创建一个新的zip文件并将zip_file的内容复制到新的zip文件中。
        let zip_file = File::open(zip_file).expect("open zip file failed");
        let mut zip_file = zip::ZipArchive::new(zip_file).expect("open zip file failed");
        let zip_file_path = File::create(zip_file_path).expect("create zip file failed");
        let mut zip_file_writer = ZipWriter::new(zip_file_path);
        for i in 0..zip_file.len() {
            let mut file = zip_file.by_index(i).expect("get file from zip failed");
            let options = FileOptions::default()
                .compression_method(file.compression())
                .unix_permissions(file.unix_mode().unwrap());

            let file_name = file.name().to_owned();
            let file_name = file_name.replace("power.conf", "power.conf");

            let content = if file_name.ends_with("power.conf") {
                buffer.clone()
            } else {
                let mut content = Vec::new();
                file.read_to_end(&mut content).expect("read file failed");
                content
            };

            zip_file_writer
                .start_file(file_name, options)
                .expect("start output file failed");
            zip_file_writer
                .write_all(&content)
                .expect("write output file failed");
        }

        zip_file_writer.finish().expect("write zip file failed");
    } else if options.export {
        let mut power_conf_path = PathBuf::new();
        power_conf_path.push(".");
        power_conf_path.push("power.conf");
        let power_conf_file = File::create(power_conf_path).expect("create power.conf failed");
        let mut writer = BufWriter::new(power_conf_file);
        writer
            .write("[Args]\n\n[Result]\n".as_bytes())
            .expect("write power.conf failed");
        writer
            .write(result.as_bytes())
            .expect("write power.conf failed");
        writer.flush().expect("write power.conf failed");
        println!("Export to power.conf completed.");
    } else {
        println!("{}", result);
    }
}
